package com.chandon.juc.thread_communication.AddStringsToList;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 描述
 *
 * @author Dong
 */

public class UseCondition {

	public static void main(String[] args) {
		useLockCondition();
	}

	static ReentrantLock reentrantLock = new ReentrantLock();
	static Condition condition = reentrantLock.newCondition();
	/**
	 * ArrayList是线程不安全的，当元素添加进去以后，还未进行更新size，就会出现问题。
	 * 可以使用线程安全的容器，如：
	 * Collections.synchronizedList(new ArrayList<>(10));
	 * 或将add方法与size方法封装成线程安全的。
	 * <p>
	 * 疑问：volatitle修饰的list是引用，没有修饰到内部的值size，为何起作用了。
	 * 猜测：被volatile关键字修饰的对象作为类变量或实例变量时，其对象中携带的类变量和实例变量也相当于被volatile关键字修饰了
	 */
	public static volatile List<String> list = new ArrayList<>(10);

	/**
	 * 4. lock condiion
	 */

	public static void useLockCondition() {


		new Thread(() -> {
			reentrantLock.lock();
			try {
				for (int i = 0; i < 10; i++) {
					// condition.signal();
					list.add("abc");
					System.out.println("list size = " + list.size());

					if (list.size() == 4) {
						System.out.println("线程B要开始了");
						condition.signal();
						condition.await();
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			reentrantLock.unlock();
		}, "线程1").start();


		new Thread(() -> {
			reentrantLock.lock();
			try {
				if (list.size() != 4) {
					condition.await();
				}
				System.out.println("线程B开始执行，list.size : " + list.size());
				condition.signal();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				reentrantLock.unlock();
			}
		}, "线程2").start();
	}

}
